import Dayjs from 'dayjs'

/**
 * 深拷贝，如果只有一个参数，则默认第一个为数据源
 * @param {Object} target
 * @param {Object} source
 * @returns
 */
 function deepCopy(target, source) {
    if (arguments.length === 1) {
        source = arguments[0];
        target = Array.isArray(source) ? [] : {};
    }
    if (!target) {
        throw Error('Cannot convert undefined or null to object');
    }
    Object.keys(source).forEach(keys => {
        if (source[keys] && typeof source[keys] === 'object') {
            target[keys] = deepCopy(source[keys])
        } else {
            target[keys] = source[keys]
        }
    })
    return target;
}

// 处理学段学科数据
function handleStageSubject (dataList, nodata = '') {
    let stageList = dataList || [];
    let str = '';
    stageList.forEach((classifyItem) => {
        let subjects = classifyItem.subjectList
            .map((item) => {
                return item.subjectName;
            })
            .join('，');
        if(subjects) {
            str += `${classifyItem.stageName}-${subjects};`
        }else{
            str += `${classifyItem.stageName};`;
        }
    });
    str = str.substring(0, str.length - 1);
    return str || nodata;
}


// 获取文件类型对应图片 没有size参数 默认小图标 带size参数 则为大图标
function fileType (type, size) {
    const data = {
        doc: require('@/assets/img/resource-type/doc.png'),
        xls: require('@/assets/img/resource-type/excel.png'),
        ppt: require('@/assets/img/resource-type/ppt.png'),
        pptx: require('@/assets/img/resource-type/ppt.png'),
        img: require('@/assets/img/resource-type/img.png'),
        files: require('@/assets/img/resource-type/files.png'),
        pdf: require('@/assets/img/resource-type/pdf.png'),
        audio: require('@/assets/img/resource-type/audio.png'),
        video: require('@/assets/img/resource-type/video.png'),
        rest: require('@/assets/img/resource-type/rest.png')
    };
    const data2 = {
        doc: require('@/assets/img/resource-type/doc@2x.png'),
        xls: require('@/assets/img/resource-type/excel@2x.png'),
        ppt: require('@/assets/img/resource-type/ppt@2x.png'),
        pptx: require('@/assets/img/resource-type/ppt@2x.png'),
        img: require('@/assets/img/resource-type/img@2x.png'),
        files: require('@/assets/img/resource-type/files@2x.png'),
        pdf: require('@/assets/img/resource-type/pdf@2x.png'),
        audio: require('@/assets/img/resource-type/audio@2x.png'),
        video: require('@/assets/img/resource-type/video@2x.png'),
        rest: require('@/assets/img/resource-type/rest@2x.png')
    };
    if (size) {
        return data2[type] ? data2[type] : data2.rest;
    } else {
        return data[type] ? data[type] : data.rest;
    }
};

/** 防抖
 * 它返回一个函数，只要它继续被调用，就不会被触发。该函数将在停止调用 N 毫秒后被调用。如果传递了`immediate`，则在前沿触发函数，而不是尾随
 * @param func - 要执行的功能
 * @param wait - 要延迟的毫秒数。
 * @param immediate - 如果为真，则在前沿触发函数，而不是在尾部触发。
 * @returns 在一定时间后调用传入的函数的函数。
 */
 function Debounce(func, wait, immediate) {
    let timeout
    wait = wait || 500
    immediate = immediate || true

    return function() {
        const context = this
        const args = arguments

        if (timeout) {
            clearTimeout(timeout);
        }
        if (immediate) {
            var callNow = !timeout
            timeout = setTimeout(() => {
                timeout = null
            }, wait)
            if (callNow) {
                func.apply(context, args);
            }
        } else {
            timeout = setTimeout(function() {
                func.apply(context, args)
            }, wait)
        }
    }
}

/**
 * 函数节流
 * @param fn
 * @param t
 * @returns {Function}
 * @constructor
 */
 function Throttle(fn, t) {
    let last;
    let timer;
    const interval = t || 500;
    return function () {
        const args = arguments;
        const now = +new Date();
        if (last && now - last < interval) {
            clearTimeout(timer);
            timer = setTimeout(() => {
                last = now;
                // console.log("实际执行函数（" + interval + "）：" + typeof fn)
                fn.apply(this, args);
            }, interval);
        } else {
            last = now;
            // console.log("实际执行函数（" + interval + "）：" + typeof fn)
            fn.apply(this, args);
        }
    };
}

/**
 * 
 * @param {number} params 
 * @returns 
 */
 function dealDynamicTime(params) {
    const dayDiff = Dayjs(Dayjs(params).format('YYYY/MM/D')).diff(
        Dayjs(Dayjs().format('YYYY/MM/D')),
        'day'
    );
    const curWeekTime = [
        Dayjs().startOf('week').add(1, 'day'),
        Dayjs().endOf('week').add(1, 'day')
    ]
    let str = '';
    switch (dayDiff) {
        case -1:
            str = `昨天 ${Dayjs(params).format('HH:mm')}`;
            break;
        case 0:
            str = `${Dayjs(params).format('HH:mm')}`;
            break;
        default: {
            if (+curWeekTime[1] >= params && params >= +curWeekTime[0]) {
                let weekArr = ['星期日', '星期一', '星期二', '星期三', '星期四', '星期五', '星期六'];
                str = `${weekArr[new Date(params).getDay()]} ${Dayjs(params).format('HH:mm')}`;
                break;
            } else if ( Number(Dayjs(params).format('YYYY')) == new Date().getFullYear() ) {
                str = `${Dayjs(params).format('MM.DD HH:mm')}`;
                break;
            } else {
                str = `${Dayjs(params).format('YYYY.MM.DD HH:mm')}`;
                break;
            }
        }
    }
    return str;
}

/**
 * 获取url上的query参数
 * @param {*} url
 * @returns
 */
 function queryToJson(url) {
    if (!url) {
        url = window.location.href;
    }
    var query = url.substr(url.lastIndexOf('?') + 1),
        result = {},
        kv,
        key,
        value,
        item;
    if (query != url && query.indexOf('&') == -1) {
        query += '&';
    }
    query.split('&').forEach((param) => {
        if (param) {
            kv = param.split('=');
            key = kv[0];
            value = kv[1];
            item = result[key];
            if (typeof item === 'undefined') {
                result[key] = value;
            } else if (
                Object.prototype.toString.call(item) === '[object Array]'
            ) {
                item.push(value);
            } else {
                result[key] = [item, value];
            }
        }
    });
    return result;
}

// 处理分类数据
function handleClassify (dataList, nodata = '') {
    let classifyList = dataList || [];
    let str = '';
    if (classifyList.length) {
        treeForEach(classifyList, (item) => {
            str = str ? str + '>' + item.name : str + item.name
        })
    }
    return str || nodata;
}

// 遍历树节点
function treeForEach(list, func) {
    let tree = list || [];
    tree.forEach(data => {
        func(data)
        data.children && treeForEach(data.children, func) // 遍历子树
    
    })
}

// 处理学段学科数据
function handleLecturers (dataList, nodata = '') {
    let list = dataList || [];
    let str = '';
    str = list.map((item) => {
        return item.name;
    })
    .join('、');
    return str || nodata;
}

class PollTask {

    constructor() {
        this.timer = null;
        this.abortState = false;
    }

    async startPoll(fn, validate, interval = 1000) {
        const resolver = async (resolve, reject) => {
          if(this.timer) {
              clearTimeout(this.timer)
          }
          try { // catch any error thrown by the "fn" function
            const result = await fn(); // fn does not need to be asynchronous or return promise
            // call validator to see if the data is at the state to stop the polling
            const valid = validate(result);
            console.log(valid);
            if (valid === true || this.abortState) {
               resolve(result);
            } else if (valid === false) {
               this.timer = setTimeout(resolver, interval, resolve, reject);
            } // if validator returns anything other than "true" or "false" it stops polling
          } catch (e) {
              clearTimeout(this.timer)
              reject(e);
          }
        };
        return new Promise(resolver);
    }

    abortPoll() {
        clearTimeout(this.timer);
        this.timer = null;
        this.abortState = true; 
    }
}

function getTargetUrl (props) {
    if(props.linkUrl) {
        return props.linkUrl;
    }
    let url = window.location.origin + '/idx/userCenter/userHomePage?uId=' + props.userId;
    return url
}

/**
 * 校验只要是数字（包含正负整数，0以及正负浮点数）就返回true
 */
function isNumber (val) {
    var regPos = /^\d+(\.\d+)?$/ // 非负浮点数
    var regNeg =
        /^(-(([0-9]+\.[0-9]*[1-9][0-9]*)|([0-9]*[1-9][0-9]*\.[0-9]+)|([0-9]*[1-9][0-9]*)))$/ // 负浮点数
    if (regPos.test(val) || regNeg.test(val)) {
        return true
    } else {
        return false
    }
}

/**
 * 浮点数位数处理，默认保留2位小数
 * @param {Number} f 需要处理的参数
 * @param {Number} digit 保留的小数点位数
 * @return {Number}
 */
function decFloat (f, digit = 2) {
    if (isNumber(f)) {
        const m = Math.pow(10, digit)
        return parseInt(decMul(f, m, -1), 10) / m
    } else {
        return 0
    }
}

/**
 * 减法
 * @param {Number} num1 被减数
 * @param {Number} num2 减数
 * @param {Number} digit 保留位数，默认保留两位小数， 传入-1为高精度计算
 * @returns {Number} 返回相减后的结果
 */
function decSub (num1 = 0, num2 = 0, digit = 2) {
    if (isNumber(num1) && isNumber(num2)) {
        const num1Digits = (num1.toString().split('.')[1] || '').length
        const num2Digits = (num2.toString().split('.')[1] || '').length
        const baseNum = Math.pow(10, Math.max(num1Digits, num2Digits)) // 放大倍数baseNum是‘两个小数点后面长度这两者之间的最大值’
        const calcValue = (decMul(num1, baseNum) - decMul(num2, baseNum)) / baseNum
        if (digit === -1) {
        return calcValue
        } else {
        return decFloat(calcValue, digit)
        }
    } else {
        return 0
    }
}

/**
 * 乘法
 * @param {Number} num1 乘数
 * @param {Number} num2 乘数
 * @param {Number} digit 保留位数，默认保留两位小数， 传入-1为高精度计算
 * @returns {Number} 返回相乘后的结果
 */
function decMul (num1 = 0, num2 = 0, digit = 2) {
    if (isNumber(num1) && isNumber(num2)) {
        const num1String = num1.toString()
        const num2String = num2.toString()
        const num1Digits = (num1String.split('.')[1] || '').length
        const num2Digits = (num2String.split('.')[1] || '').length
        const baseNum = Math.pow(10, num1Digits + num2Digits) // 放大倍数baseNum是‘两个小数点后面长度之和’

        const calcValue =
        (Number(num1String.replace('.', '')) *
            Number(num2String.replace('.', ''))) /
        baseNum
        if (digit === -1) {
        return calcValue
        } else {
        return decFloat(calcValue, digit)
        }
    } else {
        return 0
    }
}

  /**
 * 除法
 * @param {Number} num1 被除数
 * @param {Number} num2 除数
 * @param {Number} digit 保留位数，默认保留两位小数， 传入-1为高精度计算
 * @returns {Number} 返回相除后的结果
 */
function decDiv (num1 = 0, num2 = 0, digit = 2) {
    if (isNumber(num1) && isNumber(num2)) {
        const num1String = num1.toString()
        const num2String = num2.toString()
        const num1Digits = (num1String.split('.')[1] || '').length
        const num2Digits = (num2String.split('.')[1] || '').length
        const baseNum = Math.pow(10, num1Digits + num2Digits) // 放大倍数baseNum是‘两个小数点后面长度之和’
        let n1 = decMul(num1, baseNum)
        let n2 = decMul(num2, baseNum)

        const calcValue = Number(n1) / Number(n2)
        if (digit === -1) {
        return calcValue
        } else {
        return decFloat(calcValue, digit)
        }
    } else {
        return 0
    }
}

/**
 * 加法
 * @param {Number} num1 加数
 * @param {Number} num2 加数
 * @param {Number} digit 保留位数，默认保留两位小数， 传入-1为高精度计算
 * @returns {Number} 返回相加后的结果
 */
function decAdd (num1, num2, digit = 2) {
    if (isNumber(num1) && isNumber(num2)) {
        const num1Digits = (num1.toString().split('.')[1] || '').length
        const num2Digits = (num2.toString().split('.')[1] || '').length
        const baseNum = Math.pow(10, Math.max(num1Digits, num2Digits)) // 放大倍数baseNum是‘两个小数点后面长度这两者之间的最大值’
        const calcValue = (decMul(num1, baseNum) + decMul(num2, baseNum)) / baseNum
        if (digit === -1) {
        return calcValue
        } else {
        return decFloat(calcValue, digit)
        }
    } else {
        return 0
    }
}

// 获取url 某个参数的值
function getQueryString(url, paraName) {
    let arrObj = url.split("?");
    if (arrObj.length > 1) {
        let arrPara = arrObj[1].split("&");
        let arr;
        for (let i = 0; i < arrPara.length; i++) {
            arr = arrPara[i].split("=");
            if (arr != null && arr[0] == paraName) {
                return arr[1];
            }
        }
        return "";
    } else {
        return "";
    }
}

// 清空已经换过的ticket信息
function clearTicket () {
    let queryStr = queryToJson(window.location.href);
    let newSearch = '?';
    for (let key in queryStr) {
        if (key !== 'ticket' && key !== 'keepCookie') {
            newSearch = newSearch + key + '=' + queryStr[key] + '&'
        }
    }
    newSearch = newSearch.slice(0, -1);
    setTimeout(() => { // 延时是因为立即执行不生效
        if (newSearch) { // 有参数修改参数
            window.history.replaceState('', '', newSearch);
        } else { // 没有参数修改路由
            window.history.replaceState('', '', window.location.pathname);
        }
    }, 500)
}

export {
    decSub,
    deepCopy,
    handleStageSubject,
    fileType,
    Throttle,
    dealDynamicTime,
    queryToJson,
    handleClassify,
    treeForEach,
    PollTask,
    Debounce,
    getTargetUrl,
    handleLecturers,
    getQueryString,
    clearTicket,
};
